// 定义调色板类型
type Palette = number[][];

// 调色板数组
const palArr: Palette[] = [
  [[0, 0, 0], [255, 255, 255]],
  [[0, 0, 0], [255, 255, 255], [127, 0, 0]],
  [[0, 0, 0], [255, 255, 255], [127, 127, 127]],
  [[0, 0, 0], [255, 255, 255], [127, 127, 127], [127, 0, 0]],
  [[0, 0, 0], [255, 255, 255]],
  [[0, 0, 0], [255, 255, 255], [220, 180, 0]],
  [[0, 0, 0]],
  [[0, 0, 0], [255, 255, 255], [0, 255, 0], [0, 0, 255], [255, 0, 0], [255, 255, 0], [255, 128, 0]]
];

// 获取最接近的颜色索引
function getNear(r: number, g: number, b: number, curPal: Palette): number {
  let ind = 0;
  let err = getErr(r, g, b, curPal[0]);
  for (let i = 1; i < curPal.length; i++) {
    const cur = getErr(r, g, b, curPal[i]);
    if (cur < err) { 
      err = cur; 
      ind = i; 
    }
  }
  return ind;
}

// 计算颜色误差
function getErr(r: number, g: number, b: number, stdCol: number[]): number {
  r -= stdCol[0];
  g -= stdCol[1];
  b -= stdCol[2];
  return r * r + g * g + b * b;
}

// 添加误差扩散值
function addVal(c: number[], r: number, g: number, b: number, k: number): number[] {
  return [c[0] + (r * k) / 32, c[1] + (g * k) / 32, c[2] + (b * k) / 32];
}

// 设置像素值
function setVal(p: ImageData, i: number, c: number, curPal: Palette): void {
  p.data[i] = curPal[c][0];
  p.data[i + 1] = curPal[c][1];
  p.data[i + 2] = curPal[c][2];
  p.data[i + 3] = 255;
}

/**
 * 处理图片 - 灰度化
 * @param isLvl 是否使用灰度处理（true为灰度，false为抖动）
 * @param isRed 是否使用红色
 * @param imageBase64 图片的base64字符串
 * @returns 处理后的图片base64字符串
 */
export function processImage(isLvl: boolean, isRed: boolean, imageBase64: string): Promise<string> {
  return new Promise((resolve, reject) => {
    try {
      // 创建图片对象
      const srcImg = new Image();
      srcImg.onload = () => {
        // 创建源画布
        const sourceCanvas = document.createElement('canvas');
        const sW = srcImg.width;
        const sH = srcImg.height;
        sourceCanvas.width = sW;
        sourceCanvas.height = sH;
        const sourceCtx = sourceCanvas.getContext('2d');
        if (!sourceCtx) {
          reject(new Error('无法创建画布上下文'));
          return;
        }
        sourceCtx.drawImage(srcImg, 0, 0, sW, sH);
        
        // 创建目标画布
        const canvas = document.createElement('canvas');
        
        // 设置边界参数（这里使用默认值，实际应用中可以从外部传入）
        const dX = 0;
        const dY = 0;
        const dW = sW;
        const dH = sH;
        
        canvas.width = dW;
        canvas.height = dH;
        const ctx = canvas.getContext('2d');
        if (!ctx) {
          reject(new Error('无法创建画布上下文'));
          return;
        }
        
        // 选择调色板（这里使用默认值，实际应用中可以从外部传入）
        const palInd = isRed ? 1 : 0;
        const curPal = palArr[palInd];
        
        // 获取源图像数据
        const pSrc = sourceCtx.getImageData(0, 0, sW, sH);
        const pDst = ctx.getImageData(0, 0, dW, dH);
        
        let index = 0;
        
        if (isLvl) {
          // 灰度处理
          for (let j = 0; j < dH; j++) {
            const y = dY + j;
            if ((y < 0) || (y >= sH)) {
              for (let i = 0; i < dW; i++, index += 4) {
                setVal(pDst, index, (i + j) % 2 === 0 ? 1 : 0, curPal);
              }
              continue;
            }
            
            for (let i = 0; i < dW; i++) {
              const x = dX + i;
              if ((x < 0) || (x >= sW)) {
                setVal(pDst, index, (i + j) % 2 === 0 ? 1 : 0, curPal);
                index += 4;
                continue;
              }
              
              const pos = (y * sW + x) * 4;
              setVal(
                pDst, 
                index, 
                getNear(pSrc.data[pos], pSrc.data[pos + 1], pSrc.data[pos + 2], curPal),
                curPal
              );
              index += 4;
            }
          }
        } else {
          // 抖动处理（Floyd-Steinberg算法）
          let aInd = 0;
          let bInd = 1;
          const errArr: number[][][] = new Array(2);
          errArr[0] = new Array(dW);
          errArr[1] = new Array(dW);
          
          for (let i = 0; i < dW; i++) {
            errArr[bInd][i] = [0, 0, 0];
          }
          
          for (let j = 0; j < dH; j++) {
            const y = dY + j;
            if ((y < 0) || (y >= sH)) {
              for (let i = 0; i < dW; i++, index += 4) {
                setVal(pDst, index, (i + j) % 2 === 0 ? 1 : 0, curPal);
              }
              continue;
            }
            
            aInd = ((bInd = aInd) + 1) & 1;
            for (let i = 0; i < dW; i++) {
              errArr[bInd][i] = [0, 0, 0];
            }
            
            for (let i = 0; i < dW; i++) {
              const x = dX + i;
              if ((x < 0) || (x >= sW)) {
                setVal(pDst, index, (i + j) % 2 === 0 ? 1 : 0, curPal);
                index += 4;
                continue;
              }
              
              const pos = (y * sW + x) * 4;
              const old = errArr[aInd][i];
              const r = pSrc.data[pos] + old[0];
              const g = pSrc.data[pos + 1] + old[1];
              const b = pSrc.data[pos + 2] + old[2];
              
              const colInd = getNear(r, g, b, curPal);
              const colVal = curPal[colInd];
              
              pDst.data[index++] = colVal[0];
              pDst.data[index++] = colVal[1];
              pDst.data[index++] = colVal[2];
              pDst.data[index++] = 255;
              
              const rErr = (r - colVal[0]);
              const gErr = (g - colVal[1]);
              const bErr = (b - colVal[2]);
              
              // 误差扩散
              if (i === 0) {
                errArr[bInd][i] = addVal(errArr[bInd][i], rErr, gErr, bErr, 7.0);
                errArr[bInd][i + 1] = addVal(errArr[bInd][i + 1], rErr, gErr, bErr, 2.0);
                errArr[aInd][i + 1] = addVal(errArr[aInd][i + 1], rErr, gErr, bErr, 7.0);
              } else if (i === dW - 1) {
                errArr[bInd][i - 1] = addVal(errArr[bInd][i - 1], rErr, gErr, bErr, 7.0);
                errArr[bInd][i] = addVal(errArr[bInd][i], rErr, gErr, bErr, 9.0);
              } else {
                errArr[bInd][i - 1] = addVal(errArr[bInd][i - 1], rErr, gErr, bErr, 3.0);
                errArr[bInd][i] = addVal(errArr[bInd][i], rErr, gErr, bErr, 5.0);
                errArr[bInd][i + 1] = addVal(errArr[bInd][i + 1], rErr, gErr, bErr, 1.0);
                errArr[aInd][i + 1] = addVal(errArr[aInd][i + 1], rErr, gErr, bErr, 7.0);
              }
            }
          }
        }
        
        // 将处理后的图像数据放回画布
        ctx.putImageData(pDst, 0, 0);
        
        // 转换为base64并返回
        const resultBase64 = canvas.toDataURL('image/png');
        resolve(resultBase64);
      };
      
      srcImg.onerror = () => {
        reject(new Error('图片加载失败'));
      };
      
      // 设置图片源
      srcImg.src = imageBase64;
    } catch (error) {
      reject(error);
    }
  });
}





/**
 * 将base64图片字符串转换为像素数组
 * @param {string} base64Str - base64格式的图片字符串
 * @param {number} width - 图片宽度
 * @param {number} height - 图片高度
 * @param {boolean} useColorMode - 是否使用7色模式，默认为false（黑白灰模式）
 * @returns {Promise<Array>} - 返回包含像素值的数组
 */
export function base64ToPixelArray(base64Str: string, width: number, height: number, useColorMode: boolean = false): Promise<number[]> {
  return new Promise((resolve, reject) => {
    // 创建Image对象加载base64图片
    const img = new Image();
    img.onload = () => {
      // 创建canvas并绘制图片
      const canvas = document.createElement('canvas');
      canvas.width = width;
      canvas.height = height;
      const ctx = canvas.getContext('2d');
      
      if (!ctx) {
        reject(new Error('无法获取canvas上下文'));
        return;
      }
      
      // 绘制图片到canvas
      ctx.drawImage(img, 0, 0, width, height);
      
      // 获取图像数据
      const imageData = ctx.getImageData(0, 0, width, height);
      const pixelArray = new Array(width * height);
      
      // 处理图像数据
      let i = 0;
      for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++, i++) {
          if (useColorMode) {
            // 7色模式
            pixelArray[i] = getVal_7color(imageData, i << 2);
          } else {
            // 黑白灰模式
            pixelArray[i] = getVal(imageData, i << 2);
          }
        }
      }
      
      resolve(pixelArray);
    };
    
    img.onerror = () => {
      reject(new Error('图片加载失败'));
    };
    
    // 设置图片源
    img.src = base64Str;
  });
}

/**
 * 获取像素值（黑白灰模式）
 * @param {ImageData} p - 图像数据
 * @param {number} i - 像素索引
 * @returns {number} - 返回像素值：0(黑)、1(白)、2(灰)或3(其他)
 */
function getVal(p: ImageData, i: number): number {
  if ((p.data[i] == 0x00) && (p.data[i + 1] == 0x00)) return 0;
  if ((p.data[i] == 0xFF) && (p.data[i + 1] == 0xFF)) return 1;
  if ((p.data[i] == 0x7F) && (p.data[i + 1] == 0x7F)) return 2;
  return 3;
}

/**
 * 获取7色模式下的像素值
 * @param {ImageData} p - 图像数据
 * @param {number} i - 像素索引
 * @returns {number} - 返回像素值：0(黑)、1(白)、2(绿)、3(蓝)、4(红)、5(黄)、6(橙)或7(其他)
 */
function getVal_7color(p: ImageData, i: number): number {
  if ((p.data[i] == 0x00) && (p.data[i + 1] == 0x00) && (p.data[i + 2] == 0x00)) return 0;
  if ((p.data[i] == 0xFF) && (p.data[i + 1] == 0xFF) && (p.data[i + 2] == 0xFF)) return 1;
  if ((p.data[i] == 0x00) && (p.data[i + 1] == 0xFF) && (p.data[i + 2] == 0x00)) return 2;
  if ((p.data[i] == 0x00) && (p.data[i + 1] == 0x00) && (p.data[i + 2] == 0xFF)) return 3;
  if ((p.data[i] == 0xFF) && (p.data[i + 1] == 0x00) && (p.data[i + 2] == 0x00)) return 4;
  if ((p.data[i] == 0xFF) && (p.data[i + 1] == 0xFF) && (p.data[i + 2] == 0x00)) return 5;
  if ((p.data[i] == 0xFF) && (p.data[i + 1] == 0x80) && (p.data[i + 2] == 0x00)) return 6;
  return 7;
}